Skip to content

chore: rolling promotion dev -> main - #2729

Closed
namastex888 wants to merge 27 commits into
mainfrom
dev
Closed

namastex888 wants to merge 27 commits into
mainfrom
dev

Conversation

@namastex888

@namastex888 namastex888 commented Jul 28, 2026 •

Copy link
Copy Markdown
Contributor

Rolling Promotion PR

Auto-maintained rolling promotion PR from dev to main.

Process:

  • This PR is automatically created and kept open
  • Human reviews and merges when ready
  • Label ready-to-merge added when all checks pass

IMPORTANT: Merge with "Create a merge commit" — NEVER squash.
Squash merging breaks history sync between dev and main,
causing the next rolling PR to show all commits again.

Human approval required for merge to production.

Summary by CodeRabbit

  • New Features
    • Added task export, task import, and task sync for roadmap-aware snapshot workflows.
    • Introduced canonical roadmap syncing with conflict/divergence handling.
    • Added full snapshot import with optional hire roster preservation.
  • Documentation
    • Updated Genie lifecycle guidance and proportional, non-zero validation scope rules.
  • Tests
    • Added coverage for lossless import/export and canonical sync across divergent histories.
  • Chores
    • Bumped package/plugin versions to 5.260729.1; updated local sync automation and git ignore rules.

lirazsiri and others added 6 commits July 28, 2026 18:38
Apply risk-proportional validation across target repositories while preserving

aggregate integration and release gates.
Cross-machine resume for the roadmap board without committing the binary
WAL database: `genie task export --write` snapshots the full genie.db
state to git-tracked .genie/roadmap.json, and `genie task import`
(--replace to overwrite) losslessly rebuilds genie.db from it on a fresh
clone. Import validates snapshot shape and schemaVersion, refuses a
non-empty database by default, and preserves row ids exactly. INDEX.md
carries the discoverable pointer for agents.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Regenerates the committed board snapshot from genie.db on every commit
(fail-open, skipped in linked worktrees and db-less fresh clones) so the
published roadmap never lags the live board.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
genie.db is now a materialization of the committed .genie/roadmap.json.
A machine-local hash baseline (.genie/roadmap-sync, gitignored) lets
`genie task sync` detect which side moved: pulled snapshot -> auto-import,
local board mutations -> export, both moved -> refuse and warn with the
two explicit resolutions (import --replace / export --write). Every
board/task verb auto-syncs fail-open and silently; pre-commit runs sync
instead of blind export, so a stale local db can never clobber the
published roadmap. Fresh clone bootstraps with any board/task command.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough
📝 Walkthrough
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 63.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects this automatic rolling promotion from dev to main and is concise and specific.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a778482881

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/lib/v5/roadmap-sync.ts Outdated
const dbChanged = marker === null || dbHash !== marker.dbHash;

if (fileChanged && (!dbChanged || !hasOperationalState(db))) {
importState(db, parsed, { replace: true });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Serialize imports with concurrent task writes

When a pull-triggered import overlaps another process updating the shared database, that write can commit after dbHash is calculated on line 103 but before this replacement transaction begins; importState(..., { replace: true }) then deletes the newly committed task state even though the sync classified the database as unchanged. Recheck the database hash while holding the write transaction, or otherwise serialize the comparison and replacement, so parallel workers cannot lose updates during auto-sync.

AGENTS.md reference: AGENTS.md:L44-L44

Useful? React with 👍 / 👎.

Comment thread .husky/pre-commit Outdated
git_common=$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null)
if [ "$git_dir" = "$git_common" ] && [ -f .genie/genie.db ] && [ -f src/genie.ts ]; then
if bun src/genie.ts task sync; then
[ -f .genie/roadmap.json ] && git add .genie/roadmap.json

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid staging pre-existing roadmap edits

When .genie/roadmap.json already has valid unstaged edits, task sync imports them successfully and this unconditional git add puts the entire file into an otherwise unrelated commit. This breaks partial-staging workflows and violates the repository requirement to preserve unrelated dirty-worktree changes; stage the file only when the hook itself exported a refreshed snapshot, without absorbing pre-existing edits.

AGENTS.md reference: AGENTS.md:L31-L31

Useful? React with 👍 / 👎.

Comment thread src/lib/v5/task-state.ts Outdated
export function importState(db: Database, snapshot: unknown, opts: { replace?: boolean } = {}): ImportSummary {
const state = validateSnapshot(db, snapshot);
const apply = db.transaction(() => {
if (hasOperationalState(db)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear metadata for every replacement import

When the destination has no operational rows but still contains metadata such as wish_sig:*, hasOperationalState(db) is false, so even import --replace skips the wipe and merges snapshot metadata with stale local keys. The resulting export is not a lossless copy of the snapshot, and a retained wish signature can later cause a false drift error; replacement imports should clear all tables regardless of whether operational rows currently exist.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/v5/roadmap-sync.ts`:
- Around line 99-148: Add cross-process locking around the entire
read-decide-write sequence in syncRoadmap, including roadmap.json parsing,
marker reads, database import/export decisions, and file/marker writes. Use an
advisory lock associated with the sync marker path, and ensure the lock is
acquired before reading either state and released on every return path,
including invalid JSON and unchanged-state branches; apply the same protection
to autoSyncBeforeCommand.

In `@src/lib/v5/task-state.ts`:
- Around line 1447-1468: Update validateSnapshot and the snapshot insertion flow
around insertSnapshotRows to validate each table row’s expected fields and value
types before binding, and convert any unexpected insertion/bind failure into
SnapshotFormatError with the table and row context. Preserve the transaction
rollback behavior and existing schema validation, while ensuring malformed
roadmap snapshot rows never escape as raw SQLite errors.

In `@src/term-commands/v5-task.ts`:
- Around line 431-436: Normalize the paths before the baseline checks in both
handleExport and handleImport. Compare the resolved canonical roadmap path with
the resolved target/source path, while preserving the existing
recordSyncBaseline(db) behavior when they refer to the same file regardless of
relative or absolute spelling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8186e0ff-d395-4ce6-9aa5-2ec415aa11dc

📥 Commits

Reviewing files that changed from the base of the PR and between 65e1622 and a778482.

⛔ Files ignored due to path filters (1)
  • CLAUDE.md is excluded by !*.md
📒 Files selected for processing (16)
  • .claude-plugin/marketplace.json
  • .genie/INDEX.md
  • .genie/roadmap.json
  • .gitignore
  • .husky/pre-commit
  • package.json
  • plugins/genie/.claude-plugin/plugin.json
  • plugins/genie/.codex-plugin/plugin.json
  • plugins/genie/package.json
  • plugins/hermes-genie/plugin.yaml
  • src/lib/v5/genie-db.ts
  • src/lib/v5/roadmap-sync.ts
  • src/lib/v5/task-state.ts
  • src/term-commands/v5-board.ts
  • src/term-commands/v5-task.test.ts
  • src/term-commands/v5-task.ts

Comment on lines +99 to +148
export function syncRoadmap(db: Database, cwd?: string): SyncResult {
const filePath = resolveRoadmapPath(cwd);
const markerPath = resolveSyncMarkerPath(cwd);
const dbState = exportState(db);
const dbHash = canonicalHash(dbState);

if (!existsSync(filePath)) {
if (!hasOperationalState(db)) return { action: 'none' };
writeFileSync(filePath, serializeSnapshot(dbState));
writeMarker(markerPath, { fileHash: dbHash, dbHash });
return { action: 'exported', message: `Published board snapshot to ${filePath}.` };
}

let parsed: unknown;
try {
parsed = JSON.parse(readFileSync(filePath, 'utf-8'));
} catch {
return {
action: 'diverged',
message: `${filePath} is not valid JSON. Fix it, or regenerate it from the local board with \`genie task export --write\`.`,
};
}
const fileHash = canonicalHash(parsed);

if (fileHash === dbHash) {
writeMarker(markerPath, { fileHash, dbHash });
return { action: 'none' };
}

const marker = readMarker(markerPath);
const fileChanged = marker === null || fileHash !== marker.fileHash;
const dbChanged = marker === null || dbHash !== marker.dbHash;

if (fileChanged && (!dbChanged || !hasOperationalState(db))) {
importState(db, parsed, { replace: true });
writeMarker(markerPath, { fileHash, dbHash: canonicalHash(exportState(db)) });
return { action: 'imported', message: `Board refreshed from ${filePath}.` };
}
if (dbChanged && !fileChanged) {
writeFileSync(filePath, serializeSnapshot(dbState));
writeMarker(markerPath, { fileHash: dbHash, dbHash });
return { action: 'exported', message: `Board snapshot ${filePath} refreshed from the local database.` };
}
const resolution =
'Resolve with `genie task import --replace` (take the snapshot) or `genie task export --write` (keep the local board).';
return {
action: 'diverged',
message: `Both the local board (genie.db) and ${filePath} changed since the last sync. Nothing was overwritten. ${resolution}`,
};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

No cross-process locking around the roadmap.json/marker read-decide-write sequence.

syncRoadmap reads the marker and roadmap.json, decides an action, then writes the file and/or marker (Lines 105-148) — and autoSyncBeforeCommand (Lines 156-170) runs this before "every board/task command" per its docstring, plus the pre-commit hook per the PR objectives. Only the DB-side mutation inside importState is protected by a SQLite transaction; the file reads/writes here have no lock. Two processes racing (e.g. a pre-commit hook firing while an interactive genie task command is mid-sync) can interleave reads and writes on roadmap.json/the marker file, defeating the "diverged branch is the whole point" guarantee the module doc describes.

Worth a file lock (e.g. flock-style advisory lock on the marker path) around the read-decide-write critical section, or an explicit documented single-process assumption if this is accepted as out of scope for now.

Also applies to: 156-170

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/v5/roadmap-sync.ts` around lines 99 - 148, Add cross-process locking
around the entire read-decide-write sequence in syncRoadmap, including
roadmap.json parsing, marker reads, database import/export decisions, and
file/marker writes. Use an advisory lock associated with the sync marker path,
and ensure the lock is acquired before reading either state and released on
every return path, including invalid JSON and unchanged-state branches; apply
the same protection to autoSyncBeforeCommand.

Comment thread src/lib/v5/task-state.ts Resolved
Comment thread src/term-commands/v5-task.ts Resolved
namastex888 and others added 5 commits July 28, 2026 18:12
…lways valid evidence

- work/review: a passing full-suite run counts as evidence; a missing
  scope rationale is a write-up gap (at most MEDIUM), never by itself
  grounds for FIX-FIRST
- wish/work/review: a repository-documented gate is by itself
  sufficient justification for its scope
- align dispatch-brief validation example and wish acceptance criterion
- mirrors regenerated via sync-plugin-skills --write
feat(skills): make validation proportional across repositories
…p content

Drop the preAction auto-sync from task/board commands — reconciliation
now runs where state actually moves: post-merge/post-rewrite import a
pulled snapshot, pre-commit exports local board changes, both fail-open
and divergence-refusing. Scope the published snapshot to roadmap content:
hire_roster (machine-local worktree paths) is excluded from roadmap.json
and preserved untouched by canonical imports; plain `task export`
stdout remains the complete database dump.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/lib/v5/roadmap-sync.ts (1)

147-151: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Db-changed export path can silently blow away a populated roadmap.json.

Unlike the "file missing" branch above (Line 116), which checks hasOperationalState(db) before writing, this branch exports whenever dbChanged && !fileChanged with no such guard. If the local genie.db is ever wiped/recreated (corruption, accidental delete) while the marker still reflects a previously-populated state, this treats it as "db changed" and overwrites the canonical, git-tracked roadmap.json with an effectively empty snapshot — which the pre-commit hook could then commit, destroying the shared roadmap for the whole team. This directly contradicts the module's stated "no silent overwrites" design.

🛡️ Proposed fix
-  if (dbChanged && !fileChanged) {
+  if (dbChanged && !fileChanged && hasOperationalState(db)) {
     writeFileSync(filePath, serializeSnapshot(dbState));
     writeMarker(markerPath, { fileHash: dbHash, dbHash });
     return { action: 'exported', message: `Board snapshot ${filePath} refreshed from the local database.` };
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/v5/roadmap-sync.ts` around lines 147 - 151, Guard the dbChanged &&
!fileChanged export branch with hasOperationalState(db), matching the
file-missing path before writing roadmap.json or its marker. When the database
lacks operational state, skip the export so an empty or recreated genie.db
cannot overwrite a populated snapshot; preserve the existing export behavior for
operational databases.
src/term-commands/v5-task.test.ts (1)

446-491: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Divergence test no longer asserts the stderr warning format.

The stderr warn: assertion was dropped from the divergence scenario, leaving only the local-state check. This is the exact refusal path pre-commit relies on to decide whether to warn the user — losing stderr coverage here weakens regression protection for that message format.

As per path instructions, "Every new CLI surface must test success, error exit code, stderr, and idempotency."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/term-commands/v5-task.test.ts` around lines 446 - 491, The divergence
scenario in the test “pulled snapshot imports on sync; local mutation exports;
divergence is refused then resolvable” must also validate the refusal warning on
stderr. After invoking sync for the diverged state, assert the expected `warn:`
message format alongside the existing exit-code, stdout, snapshot, and
local-state assertions.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/v5/task-state.ts`:
- Around line 1580-1586: Update the snapshot wipe flow around insertSnapshotRows
so preserveHireRoster truly protects existing hire_roster rows when wish_groups
and boards are deleted and recreated. Inspect the hire_roster schema and
foreign-key relationships, then prevent those deletions from cascading into or
violating preserved hires while retaining the current wipe behavior for
non-preserved data.

---

Outside diff comments:
In `@src/lib/v5/roadmap-sync.ts`:
- Around line 147-151: Guard the dbChanged && !fileChanged export branch with
hasOperationalState(db), matching the file-missing path before writing
roadmap.json or its marker. When the database lacks operational state, skip the
export so an empty or recreated genie.db cannot overwrite a populated snapshot;
preserve the existing export behavior for operational databases.

In `@src/term-commands/v5-task.test.ts`:
- Around line 446-491: The divergence scenario in the test “pulled snapshot
imports on sync; local mutation exports; divergence is refused then resolvable”
must also validate the refusal warning on stderr. After invoking sync for the
diverged state, assert the expected `warn:` message format alongside the
existing exit-code, stdout, snapshot, and local-state assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 445ad893-b474-44ce-bfe7-b263c8e07ca9

📥 Commits

Reviewing files that changed from the base of the PR and between f743ec3 and e2659dc.

⛔ Files ignored due to path filters (1)
  • CLAUDE.md is excluded by !*.md
📒 Files selected for processing (8)
  • .genie/INDEX.md
  • .husky/post-merge
  • .husky/post-rewrite
  • .husky/pre-commit
  • src/lib/v5/roadmap-sync.ts
  • src/lib/v5/task-state.ts
  • src/term-commands/v5-task.test.ts
  • src/term-commands/v5-task.ts

Comment thread src/lib/v5/task-state.ts Resolved
lirazsiri and others added 8 commits July 28, 2026 18:51
…s exempt

Maintainer revision of the bypass policy, rebased onto dev:

- every bypass is announced in one line with a 'use genie' override
- security-sensitive changes keep lifecycle review gates by default;
  only an explicit user choice skips them
- bug reports (report), operational commands, and Genie questions are
  cheap and never bypassed — resolves the contradiction with the
  intent-classification table and skill catalog
- value-gate criteria get a worked example each; uncertainty inspection
  bounded to the two ls commands plus files the request names
- skill description keeps bug/question routing discoverable
- content-contract test pins policy invariants instead of full sentences
- mirrors regenerated via sync-plugin-skills --write
fix(router): bypass Genie when lifecycle adds no value
…onical board

Design SHIP (1 fix loop, digest 36097b0d…), plan SHIP (2 fix loops, all
findings execution-verified). 3-scout audit: 29 wishes DONE-verified on
dev, 5 in progress, 2 open. Plan: archive 29 with link-rewrite inventory,
cold-seed roadmap board with 19 lifecycle cards (Felipe-ratified work
order), rewrite INDEX with Shipped section, draft public-roadmap-polish.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@namastex888

Copy link
Copy Markdown
Contributor Author

@codex review this pr

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e7a1dfb68d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .husky/post-merge
Comment on lines +8 to +9
if [ "$git_dir" = "$git_common" ] && [ -f src/genie.ts ] && [ -f .genie/roadmap.json ]; then
bun src/genie.ts task sync || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reconcile the snapshot after checkout

When the main checkout switches between branches containing different .genie/roadmap.json versions, neither this hook nor post-rewrite runs, so the shared genie.db continues exposing the previous branch's board until a manual sync or pre-commit. Any intervening task list, claim, or mutation therefore operates on stale state and can cause divergence; the checked .husky hook set needs the same reconciliation in a user post-checkout hook, which Git documents as running after checkout updates the worktree.

Useful? React with 👍 / 👎.

Comment on lines +482 to +484
// The canonical snapshot is roadmap-scoped: local hires stay untouched.
const canonical = source === resolveRoadmapPath();
const summary = importState(db, snapshot, { replace: opts.replace, preserveHireRoster: canonical });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve hires when the canonical path is explicit

When a user runs genie task import .genie/roadmap.json --replace, source is relative while resolveRoadmapPath() is absolute, so this comparison marks the actual canonical snapshot as non-canonical. The import consequently wipes the machine-local hire_roster and skips recording the sync baseline, even though omitting the identical filename preserves hires; compare normalized absolute paths rather than raw strings.

Useful? React with 👍 / 👎.

Comment thread src/term-commands/v5-task.ts Outdated
Comment on lines +431 to +433
// --write publishes the roadmap slice (no hire_roster — machine-local
// worktree paths); the plain stdout dump stays the complete database.
const state = opts.write ? roadmapSnapshot(db) : exportState(db);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep custom-file exports lossless

When genie task export --write backup.json is used, this branch selects roadmapSnapshot() and silently removes hire_roster, whereas plain task export emits complete state and importing a custom file treats it as a full snapshot. An ensuing task import backup.json --replace therefore deletes all hire/worktree bindings, so only the canonical roadmap export should omit hires or the custom-file import/export contract must preserve them consistently.

Useful? React with 👍 / 👎.

Comment thread .hermes/config.yaml
@@ -0,0 +1,16 @@
model:
default: gpt-5.6-sol

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove the unstable Codex model pin

Because this repository-local Hermes profile uses the openai-codex provider, setting a release-specific model ID forces every session away from the client's active model and will fail or become stale where that identifier is unavailable. Let the provider inherit the active model instead of committing this pin.

AGENTS.md reference: AGENTS.md:L37-L37

Useful? React with 👍 / 👎.

namastex888 and others added 3 commits July 28, 2026 22:04
…lugin is enabled

syncClaude computed pluginEnabled and used it to suppress the bare-name
skills mirror, but never passed it to syncClaudeAgentFiles. Role agents
were fanned into ~/.claude/agents unconditionally while the plugin also
served the same files as genie:*, so all seven double-listed in the agent
picker — the exact waste the skills-mirror hotfix removed.

Pass pluginEnabled through and feed syncClaudeAgentFiles an empty source
set when it is true. Every manifest-owned file then flows through the
existing planAgentOrphan path, which backs the bytes up before retiring
them and preserves hand-edited files as kept-modified-orphan. The
GENIE_FORCE_CLAUDE_SKILLS_MIRROR kill-switch already gates both surfaces
because it lives inside claudeGeniePluginEnabled.

Doctor is updated to match: with the plugin enabled the expected source
set is empty, so a surviving fan-out reads as prunable stale rather than
current, and a pruned one passes instead of reporting seven
missing-from-target and advising `genie update` forever. The duplicate
surface warning now tracks leftover files rather than merely the plugin
being enabled, and points at the sync suggestion that actually resolves
it. checkRoleAgents now uses claudeGeniePluginEnabled, dropping a
duplicate settings reader that ignored the kill-switch.
…ware

fix(agent-sync): suppress the bare-name role-agent fan-out when the plugin is enabled

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/genie-commands/doctor.ts (1)

1108-1117: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Detect unmanaged role-agent files while suppression is active.

When suppressed empties source, names is built only from source keys and manifest entries. A fresh user-created agents/reviewer.md with no manifest entry is therefore never classified, so duplicateSurface stays false even though genie:reviewer and bare reviewer are both visible. Retain the source role-name set for discovery while using an empty digest map for suppression comparisons, or otherwise include matching on-disk files.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/genie-commands/doctor.ts` around lines 1108 - 1117, Update the agent
discovery logic around sourceState, source, and names so suppression uses an
empty digest map for comparison but retains the unsuppressed source role-name
set for discovery. Include matching on-disk bare role-agent files such as
reviewer.md even without manifest entries, allowing duplicateSurface to detect
both genie:reviewer and reviewer while preserving prunable-leftover handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.genie/brainstorms/genie-official-roadmap/DESIGN.md:
- Around line 88-95: Refresh the Reviewed content SHA-256 in the bounded
genie-design-review block to match the current DESIGN.md content with that block
removed. Preserve the existing SHIP verdict and review metadata, and only retain
the verdict once the digest is accurate.

In @.genie/wishes/genie-official-roadmap/WISH.md:
- Around line 129-130: Strengthen the roadmap validation commands in the
documented checks: replace aggregate task-count and non-null-lane assertions
with exact expected title/lane pairs for all roadmap tasks, and update the
doctor validation to filter results to the expected roadmap slugs before
asserting the required number of ok entries. Apply the same correction to the
additional check at the referenced later section.
- Line 191: Propagate the post-approval execution amendment throughout the
earlier plan for genie-official-roadmap: update every enumeration, command,
count, and acceptance criterion that places its own card in Brainstorm or its
INDEX entry in Raw, including the sections around the referenced plan lines, to
use Wish and Poured respectively. Preserve all other placements and ensure the
final board/INDEX checks and ok>=18 threshold reflect the amended state.

In @.hermes/config.yaml:
- Around line 1-4: Update the model.default setting in the Hermes configuration
to use the documented active-model inheritance value instead of hardcoding
gpt-5.6-sol. Keep the openai-codex provider and base_url unchanged, and ensure
Codex agents inherit the caller’s active session model.

In @.hermes/SOUL.md:
- Around line 18-20: Update the command guidance in SOUL.md to prohibit only the
obsolete top-level genie serve command, while explicitly allowing the supported
genie omni serve command documented in the lifecycle references. Keep the
existing prohibitions for the other obsolete surfaces unchanged.

In `@scripts/release-docs.test.ts`:
- Around line 976-993: Update the test “router pays Genie lifecycle cost only
when it adds value” to assert that the router metadata loaded from
“skills/genie/agents/openai.yaml” contains the security-sensitive bypass rule,
matching the existing SKILL.md and lifecycle assertions.

In `@skills/genie/SKILL.md`:
- Around line 49-53: Update the State Detection guidance in both
skills/genie/SKILL.md (lines 49-53) and plugins/genie/skills/genie/SKILL.md
(lines 49-53) to read the matched WISH.md or brainstorm handoff, within a
bounded scope, before applying the status-specific routing override; retain the
existing slug listing/matching and routing behavior in both copies.

In `@src/lib/agent-sync.ts`:
- Around line 5674-5682: Update syncClaudeAgentFiles to return a status
indicating whether synchronization committed changes or is already converged,
including unsafe-manifest and committed === false outcomes. In the caller, emit
the agents-mirror suppressed report entry only when that returned status
confirms a committed or already-converged state; otherwise leave the suppression
report absent.

---

Outside diff comments:
In `@src/genie-commands/doctor.ts`:
- Around line 1108-1117: Update the agent discovery logic around sourceState,
source, and names so suppression uses an empty digest map for comparison but
retains the unsuppressed source role-name set for discovery. Include matching
on-disk bare role-agent files such as reviewer.md even without manifest entries,
allowing duplicateSurface to detect both genie:reviewer and reviewer while
preserving prunable-leftover handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c4cb9fe8-a3d5-47df-b70e-79177292c738

📥 Commits

Reviewing files that changed from the base of the PR and between 0696e9c and 9be108a.

📒 Files selected for processing (27)
  • .claude-plugin/marketplace.json
  • .genie/INDEX.md
  • .genie/brainstorms/genie-official-roadmap/DESIGN.md
  • .genie/brainstorms/genie-official-roadmap/DRAFT.md
  • .genie/roadmap.json
  • .genie/wishes/genie-official-roadmap/WISH.md
  • .gitignore
  • .hermes/SOUL.md
  • .hermes/config.yaml
  • .hermes/profile.yaml
  • biome.json
  • package.json
  • plugins/genie/.claude-plugin/plugin.json
  • plugins/genie/.codex-plugin/plugin.json
  • plugins/genie/package.json
  • plugins/genie/skills/genie/SKILL.md
  • plugins/genie/skills/genie/agents/openai.yaml
  • plugins/genie/skills/genie/reference/lifecycle.md
  • plugins/hermes-genie/plugin.yaml
  • scripts/release-docs.test.ts
  • skills/genie/SKILL.md
  • skills/genie/agents/openai.yaml
  • skills/genie/reference/lifecycle.md
  • src/genie-commands/doctor.test.ts
  • src/genie-commands/doctor.ts
  • src/lib/agent-sync.test.ts
  • src/lib/agent-sync.ts

Comment on lines +129 to +130
genie board --board roadmap && genie task export | bun -e 'const s=JSON.parse(await Bun.stdin.text());const b=s.boards.find(x=>x.name==="roadmap");if(!b)process.exit(1);const c=s.tasks.filter(t=>t.board_id===b.id);if(c.length!==19||c.some(t=>!t.lane))process.exit(1)'
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Validate the expected roadmap set, not just aggregate counts.

The board check accepts any 19 tasks with non-null lanes, even if titles or lanes are wrong. The doctor check counts 18 ok entries globally, so unrelated entries can satisfy the threshold while the roadmap entries remain unresolved. Assert the exact title/lane pairs and filter doctor results to the expected roadmap slugs.

Also applies to: 154-156

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.genie/wishes/genie-official-roadmap/WISH.md around lines 129 - 130,
Strengthen the roadmap validation commands in the documented checks: replace
aggregate task-count and non-null-lane assertions with exact expected title/lane
pairs for all roadmap tasks, and update the doctor validation to filter results
to the expected roadmap slugs before asserting the required number of ok
entries. Apply the same correction to the additional check at the referenced
later section.

Comment thread .hermes/config.yaml
Comment on lines +1 to +4
model:
default: gpt-5.6-sol
provider: openai-codex
base_url: https://chatgpt.com/backend-api/codex

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Do not pin an unstable Codex model identifier.

model.default hardcodes gpt-5.6-sol, which can override the active session model and become unavailable independently of the caller. Use Hermes’ documented active-model inheritance setting instead.

As per coding guidelines, Codex agents inherit the active model and must not hardcode unstable model identifiers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.hermes/config.yaml around lines 1 - 4, Update the model.default setting in
the Hermes configuration to use the documented active-model inheritance value
instead of hardcoding gpt-5.6-sol. Keep the openai-codex provider and base_url
unchanged, and ensure Codex agents inherit the caller’s active session model.

Source: Coding guidelines

Comment thread .hermes/SOUL.md Resolved
Comment thread scripts/release-docs.test.ts Resolved
Comment thread skills/genie/SKILL.md Resolved
Comment thread src/lib/agent-sync.ts
Comment on lines +5674 to +5682
syncClaudeAgentFiles(ctx, claudeDir, report, pluginEnabled);
if (pluginEnabled) {
report.extras.push({
kind: 'agents-mirror',
action: 'suppressed',
detail:
'genie@automagik plugin enabled — bare-name role-agent fan-out pruned; agents load as genie:* from the plugin',
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Only report suppression after the sync succeeds.

syncClaudeAgentFiles can leave files untouched for an unsafe manifest or record result.committed === false, but this caller still emits agents-mirror: suppressed. The report can therefore claim the duplicate surface was pruned when it remains present. Return a success/status result from the sync function and emit this extra only after a committed or already-converged state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/agent-sync.ts` around lines 5674 - 5682, Update syncClaudeAgentFiles
to return a status indicating whether synchronization committed changes or is
already converged, including unsafe-manifest and committed === false outcomes.
In the caller, emit the agents-mirror suppressed report entry only when that
returned status confirms a committed or already-converged state; otherwise leave
the suppression report absent.

namastex888 and others added 2 commits July 29, 2026 00:39
…2732)

The test called runManualUpdateConvergence without a selection, so the
default resolved the host machine's persisted integration consent
(~/.genie/.integration-consent.json). On a codex-consent machine the
agent-sync arm narrows to null, runSync never fires, and the test fails
— while CI (no consent file) and all/auto machines pass. Same commit,
same binary, different machine state.

Pass selection: 'all' explicitly, matching every other caller in this
file (the codex-only, auto, and hermes-leg tests already pin theirs).

Closes #2732
- task export/import: resolve explicit paths before the canonical
  comparison, so a relative spelling of .genie/roadmap.json preserves
  local hires and records the sync baseline
- task export --write <file>: custom-file backups emit the complete
  state including hire_roster; only canonical roadmap.json gets the
  roadmap slice, keeping backup round-trips lossless
- importState: --replace wipes all tables even when only meta rows
  exist, so stale wish_sig/backfill markers cannot merge into the
  snapshot; malformed rows that pass shape validation rethrow as
  SnapshotFormatError after rollback
- syncRoadmap: compare-and-act runs under BEGIN IMMEDIATE, closing the
  window where a concurrent task write could be destroyed by a
  replace-import and serializing concurrent syncs
- pre-commit: stage roadmap.json only when sync itself rewrote it,
  never absorbing pre-existing unstaged edits
- post-checkout (new hook): run task sync after branch checkouts so the
  shared db stops exposing the previous branch's board
- .hermes/SOUL.md: narrow the obsolete-serve prohibition so it cannot
  be read as banning the supported 'genie omni serve'
- release-docs.test.ts: assert the security-sensitive bypass rule in
  router metadata too

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
automagik-genie and others added 3 commits July 29, 2026 00:49
…solation

fix(test): pin selection in the manual post-update convergence test
fix(v5): harden roadmap sync per PR #2729 bot-review findings
@coderabbitai coderabbitai Bot mentioned this pull request Jul 29, 2026
namastex888 added a commit that referenced this pull request Jul 30, 2026
- task export/import: resolve explicit paths before the canonical
  comparison, so a relative spelling of .genie/roadmap.json preserves
  local hires and records the sync baseline
- task export --write <file>: custom-file backups emit the complete
  state including hire_roster; only canonical roadmap.json gets the
  roadmap slice, keeping backup round-trips lossless
- importState: --replace wipes all tables even when only meta rows
  exist, so stale wish_sig/backfill markers cannot merge into the
  snapshot; malformed rows that pass shape validation rethrow as
  SnapshotFormatError after rollback
- syncRoadmap: compare-and-act runs under BEGIN IMMEDIATE, closing the
  window where a concurrent task write could be destroyed by a
  replace-import and serializing concurrent syncs
- pre-commit: stage roadmap.json only when sync itself rewrote it,
  never absorbing pre-existing unstaged edits
- post-checkout (new hook): run task sync after branch checkouts so the
  shared db stops exposing the previous branch's board
- .hermes/SOUL.md: narrow the obsolete-serve prohibition so it cannot
  be read as banning the supported 'genie omni serve'
- release-docs.test.ts: assert the security-sensitive bypass rule in
  router metadata too

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants